using System;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using AntEater.ComponentModel.BuildElements;

namespace AntEater.ComponentModel
{
    /// <summary>
    /// Provides some general helper methods.
    /// </summary>
    public static class Utilities
    {
        /// <summary>
        /// Gets the Attributes of Type TAttribute from the provided attributeOwner.
        /// </summary>
        /// <typeparam name="TAttribute">Attribute Type to get.</typeparam>
        /// <param name="attributeOwner">Object whose Type owns the Attribute.</param>
        /// <returns>An array containing the requested Attribute.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        public static TAttribute[] GetTypeAttributesFromObject<TAttribute>(object attributeOwner)
            where TAttribute : Attribute {
            return GetTypeAttributesFromType<TAttribute>(attributeOwner.GetType());
        }

        /// <summary>
        /// Gets the Attribute of Type TAttribute from the provided attributeOwner.
        /// </summary>
        /// <typeparam name="TAttribute">Attribute Type to get.</typeparam>
        /// <param name="attributeOwner">Object whose Type owns the Attribute.</param>
        /// <returns>The requested Attribute or Null if the Attribute is not present.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        public static TAttribute GetTypeAttributeFromObject<TAttribute>(object attributeOwner)
            where TAttribute : Attribute {
            return GetTypeAttributeFromType<TAttribute>(attributeOwner.GetType());
        }

        /// <summary>
        /// Gets the Attribute of Type TAttribute from the provided attributeOwner.
        /// </summary>
        /// <typeparam name="TAttribute">Attribute Type to get.</typeparam>
        /// <param name="attributeOwner">Type which owns the Attribute.</param>
        /// <returns>The requested Attribute or Null if the Attribute is not present.</returns>
        [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        public static TAttribute GetTypeAttributeFromType<TAttribute>(Type attributeOwner)
            where TAttribute : Attribute {

            TAttribute attribute = null;

            TAttribute[] attributes = GetTypeAttributesFromType<TAttribute>(attributeOwner);

            if (attributes.Length > 0) {
                attribute = attributes[0];
            }

            return attribute;
        }

        /// <summary>
        /// Gets the Attributes of Type TAttribute from the provided attributeOwner.
        /// </summary>
        /// <param name="attributeOwner">The attribute owner.</param>
        /// <returns>An array containing the requested Attribute.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
        public static TAttribute[] GetTypeAttributesFromType<TAttribute>(Type attributeOwner)
            where TAttribute : Attribute {

            TAttribute[] attributes 
                = attributeOwner.GetCustomAttributes(typeof(TAttribute), true) as TAttribute[];

            return attributes;
        }

        /// <summary>
        /// Gets the Attribute of Type TAttribute for an Property of the provided Object.
        /// </summary>
        /// <typeparam name="TAttribute">Attribute Type to get.</typeparam>
        /// <param name="attributeOwner">Type which owns the Property.</param>
        /// <param name="propertyName">Name of the Property which owns the Attribute.</param>
        /// <returns>The requested Attribute or Null if the Attribute is not present.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        public static TAttribute GetPropertyAttributeFromObject<TAttribute>(object attributeOwner, string propertyName)
            where TAttribute : Attribute {
            return GetPropertyAttributeFromType<TAttribute>(attributeOwner.GetType(), propertyName);
        }

        /// <summary>
        /// Gets the Attribute of Type TAttribute for an Property of the provided Type.
        /// </summary>
        /// <typeparam name="TAttribute">Attribute Type to get.</typeparam>
        /// <param name="attributeOwner">Type which owns the Property.</param>
        /// <param name="propertyName">Name of the Property which owns the Attribute.</param>
        /// <returns>The requested Attribute or Null if the Attribute is not present.</returns>
        [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
        public static TAttribute GetPropertyAttributeFromType<TAttribute>(Type attributeOwner, string propertyName)
            where TAttribute : Attribute {
            TAttribute attribute = null;

            PropertyInfo propertyInfo = attributeOwner.GetProperty(propertyName);

            if (propertyInfo != null) {
                TAttribute[] attributes = propertyInfo.GetCustomAttributes(typeof(TAttribute), true) as TAttribute[];

                if (attributes.Length > 0) {
                    attribute = attributes[0];
                }
            }
            return attribute;
        }

        /// <summary>
        /// Gets the tool tip text of the specified build element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The ToolTip Text.</returns>
        public static string GetBuildElementToolTipText(IBuildElement element) {

            if (element == null) { throw new ArgumentNullException("element"); }

            string toolTipText = element.ToString();

            Type buildElementType = element.GetType();

            foreach (PropertyInfo propertyInfo in buildElementType.GetProperties()) {
                if (Attribute.IsDefined(propertyInfo, typeof(ToolTipAttribute), true)) {
                    toolTipText = propertyInfo.GetValue(element, null) as string;
                }
            }

            return toolTipText;
        }
    }
}
